home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / BG_SRC.ZIP / BG.C < prev    next >
C/C++ Source or Header  |  1994-05-24  |  18KB  |  588 lines

  1. /*
  2.  *
  3.  *                            B  G  .  C
  4.  * O.F.Ransen:    21st June  1991
  5.  * This version:  27th April 1994
  6.  *
  7.  *
  8.  */
  9.  
  10. #include "comp.h"
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <stdio.h>
  14. #include <conio.h>
  15. #include <time.h>
  16. #include "bg.h"
  17. #include "mousy.h"
  18.  
  19. FILE*   Rec_File   = NULL ;
  20. boolean Debugging  = FALSE ; /* If writing moves to a file     */
  21. boolean Genetics   = FALSE ; /* If doing Darwininian selection */
  22. boolean F10_Hit    = FALSE ; /* Recieves F10 key from anywhere */
  23.  
  24. extern Stats_t Statistics [N_PLAYERS] ;
  25. extern int     Target_Score ;
  26.  
  27. /*************************************************************************/
  28.  
  29. static void    Open_Record_File (ushort n) ;
  30. static void    Swap_Players (Player_t* Pa, Player_t* Pb) ;
  31. static void    Command_Line_Read (int argc, char* argv[]) ;
  32. static void    Update_Score (Player_t Player, int Points) ;
  33. static boolean Game_Over (Player_t Human) ;
  34.  
  35. /*************************************************************************/
  36.  
  37. void main (int argc, char* argv[])
  38. {
  39.     boolean  Running ;
  40.     Speed_t  Speed ;
  41.     short    Opponent ;
  42.     Player_t Human ; /* WHITE_PLAYER or BLACK_PLAYER */
  43.  
  44.     Check_Mouse () ;
  45.     Command_Line_Read (argc,argv) ;
  46.  
  47.     Set_Ctl_C_Handler () ;
  48.  
  49.     Decode_And_Show_Titles () ;
  50.     Print_Message (HAKTOC_MSG) ;
  51.     (void)Get_Key() ;
  52.  
  53.     Init_Stats () ;
  54.     Init_Rannum_Gen () ;
  55.     Init_Graphics () ;
  56.     Start_Up_Mouse () ;
  57.     Randomise () ;
  58.  
  59.     if (Genetics) {
  60.         Genetic_Selection () ;
  61.     } else {
  62.         Opponent = SERGIO ;
  63.         Human    = BLACK_PLAYER ;
  64.         Speed    = SLOW_SPEED ;
  65.  
  66.         Running = First_Interaction (&Speed,&Human,&Opponent) ;
  67.  
  68.         while (Running) {
  69.             boolean Playing ;
  70.             Init_Stats () ;
  71.             Playing = TRUE ;
  72.             while (Playing) {
  73.                 Print_Players (Opponent,Human) ;
  74.                 Playing = Play_The_Game (Speed,Human,Opponent) ;
  75.             }
  76.             Running = Top_Level_Interact (&Speed,&Human,&Opponent) ;
  77.         }
  78.     }
  79.     Go_Text_Mode () ;
  80.     Show_Titles () ;
  81. }
  82.  
  83. /*************************************************************************/
  84.  
  85. boolean Play_The_Game (Speed_t Speed, Player_t Human, short O_Index)
  86. /*
  87. PURPOSE: To play a single game of backgammon, returning TRUE while
  88.          the target score has not been reached. We return FALSE when
  89.          the target score has been reached or when the user hits F10.
  90. NOTES:   2) If Human!=NULL_PLAYER then the Human is either red or
  91.          white and wants to play against the computer.
  92. */
  93. {
  94.     Layout_t  Curr_Lay[2] ; /* The current layouts */
  95.     Transit_t Transit[2] ; /* The new layouts and how we got there */
  96.     Player_t  Opponent,Player,Starter ;
  97.     boolean   First_Loop,  /* Dice already thrown, just move */
  98.               Finished,    /* Game over */
  99.               Can_Move,    /* Move possible with these dice */
  100.               Doubled,     /* Current player doubled stakes */
  101.               Rejected ;   /* Current opponent rejected stakes */
  102.     extern    Player_t Double_Possessor ;
  103.     extern    int      Double_Value ;
  104.     extern    int      N_Moves ;
  105.     Dice_t    Dice ;
  106.     char      User_Char ;
  107.     short     Points ;
  108.  
  109.     if (Debugging) {
  110.         Open_Record_File (0) ;
  111.     }
  112.  
  113. #if DRODBAR
  114.     Test_Move () ;
  115. #endif
  116.  
  117.     N_Moves          = 0 ;  // Helps to decide when to double
  118.     Double_Value     = 1 ;  /* No double yet */
  119.     Double_Possessor = NULL_PLAYER ;
  120.  
  121.     Initial_Board   (Curr_Lay) ;
  122.     Draw_Board_Full (Curr_Lay) ;
  123.  
  124.     if (!Genetics) {
  125.         Show_Opponents_Face (Curr_Lay,Human,O_Index) ;
  126.         Draw_Eyes (2,O_Index) ;
  127.     }
  128.  
  129.     Select_Starter (&Starter,&Dice) ;
  130.     if (F10_Hit) {
  131.         F10_Hit = FALSE ;
  132.         return (F10_KEY) ;
  133.     }
  134.     Player     = Starter ;
  135.     Opponent   = OPPONENT(Starter) ;
  136.     First_Loop = TRUE ; /* So we don't throw the dice again */
  137.  
  138.     Finished   = FALSE ;
  139.     User_Char  = 0 ; /* Not Escape yet */
  140.     Print_Message (HELP_MSG) ;
  141.  
  142.     do {
  143.         if (!First_Loop) {
  144.             /* Have to throw the dice */
  145.             if (Move_Possible (Curr_Lay[Player],Curr_Lay[Opponent])) {
  146.                 /* It is worth throwing the dice */
  147.                 Dice = Throw_Dice (Player,Opponent,Human,&Doubled,&Rejected,Curr_Lay) ;
  148.                 if (F10_Hit) {
  149.                     F10_Hit = FALSE ;
  150.                     return (FALSE) ;
  151.                 }
  152.                 if (Doubled && Rejected) {
  153.                     /* Opponent rejected the double, so Player wins */
  154.                     Update_Score (Player,1) ;
  155.                     Show_Winner (Player,Human,1) ;
  156.                     Finished  = TRUE ;
  157.                     Can_Move  = FALSE ;
  158.                     /*
  159.                      * See if we have finished the whole set.
  160.                      */
  161.                     if (Game_Over (Human)) {
  162.                         return (FALSE) ;
  163.                     } else {
  164.                         User_Char = (char)Key_And_Delay (3) ; /* Wait a bit */
  165.                         return (User_Char != F10_KEY) ;
  166.                     }
  167.                 } else {
  168.                     Draw_Dice_Pair (&Dice,Player) ;
  169.                     if (!Genetics) {
  170.                         Draw_Eyes (Dice.N_Vals,O_Index) ;
  171.                     }
  172.                     Can_Move = TRUE ;
  173.                 }
  174.             } else {
  175.                 /* Move is not possible */
  176.                 if (Player == WHITE_PLAYER) {
  177.                     Print_Message (W_NOGO_MSG) ;
  178.                 } else {
  179.                     Print_Message (B_NOGO_MSG) ;
  180.                 }
  181.                 Seconds_Delay (2) ;
  182.                 Swap_Players (&Player,&Opponent) ;
  183.                 Finished = FALSE ;
  184.                 Can_Move = FALSE ;
  185.             }
  186.         } else {
  187.             /* Dice already thrown for us */
  188.             Can_Move = TRUE ;
  189.             First_Loop = FALSE ;
  190.         }
  191.  
  192.         if (Can_Move) {
  193.             Draw_Stats () ;
  194.             if (Player == Human) {
  195.                 User_Char = User_Selects_Move (&Dice,
  196.                            Curr_Lay [Player], Curr_Lay [Opponent],
  197.                            &Transit [Player], &Transit [Opponent],
  198.                            Player) ;
  199.                 if (User_Char == F10_KEY) {
  200.                     F10_Hit = FALSE ;
  201.                     return (FALSE) ;
  202.                 }
  203.             } else {
  204.                 if (Human != NULL_PLAYER) {
  205.                     Seconds_Delay (2) ; /* So man can sees computers dice */
  206.                 }
  207.                 Select_Best_Move (&Dice,
  208.                           Curr_Lay [Player], Curr_Lay [Opponent],
  209.                           &Transit [Player], &Transit [Opponent],
  210.                           Player,Bestest) ;
  211.             }
  212.  
  213.             Copy_Layout (Curr_Lay [Player],  Transit[Player].Layout) ;
  214.             Copy_Layout (Curr_Lay [Opponent],Transit[Opponent].Layout) ;
  215.             if (!Genetics) {
  216.                 Show_Opponents_Face (Curr_Lay,Human,O_Index) ;
  217.             }
  218.  
  219.             if (Player != Human) {
  220.                 /* Show the human how the computer moved */
  221.                 User_Char = Show_Transits_And_Kb_Look (&Transit [Player],
  222.                                                          &Transit [Opponent],
  223.                                                        Player,Speed) ;
  224.                 Draw_Board_Quick (Curr_Lay[BLACK_PLAYER],Curr_Lay[WHITE_PLAYER]) ;
  225.             }
  226.  
  227.             if (Debugging) {
  228.                 Record_Move (Player,&Dice,Curr_Lay[BLACK_PLAYER],Curr_Lay[WHITE_PLAYER]) ;
  229.             }
  230.  
  231.             Finished = (User_Char == F10_KEY) ;
  232.             Points = Won (Curr_Lay[Player],Curr_Lay[Opponent]) ;
  233.             if (Points > NO_WIN) {
  234.                 Update_Score (Player,Points) ;
  235.                 Show_Winner (Player,Human,Points) ;
  236.                 Finished  = TRUE ;
  237.                 /*
  238.                  * See if we have finished the whole set.
  239.                  */
  240.                 if (Game_Over (Human)) {
  241.                     return (FALSE) ;
  242.                 } else {
  243.                     User_Char = (char)Key_And_Delay (2) ;
  244.                     return (User_Char != F10_KEY) ;
  245.                 }
  246.             } else {
  247.                 Swap_Players (&Player,&Opponent) ;
  248.             }
  249.         }
  250.         N_Moves++ ;
  251.     } while (!Finished) ;
  252.  
  253.     if (Debugging) {
  254.         fclose (Rec_File) ;
  255.         Rec_File = NULL ;
  256.     }
  257.  
  258.     return (User_Char != F10_KEY) ;
  259. }
  260.  
  261. /*************************************************************************/
  262.  
  263. void Select_Starter (Player_t* Player, Dice_t* Dice)
  264. /*
  265. PURPOSE: To select who will start the game, with graphics. We return who
  266. starts the game in Player, and the dice with which he starts in Dice.
  267. */
  268. {
  269.     int Black_Score,White_Score,Rand_Rolls,r ;
  270.     extern Throw_t Throw ;
  271.     Dice_t Temp_Dice ;
  272.  
  273.     if (Throw == MANUAL_THROW) {
  274.         do {
  275.             Temp_Dice = Human_Throws_Dice (BLACK_PLAYER,WHITE_PLAYER) ;
  276.             if (F10_Hit) {
  277.                 return ;
  278.             }
  279.         } while (Temp_Dice.Values[0] == Temp_Dice.Values[1]) ;
  280.  
  281.         Copy_Dice (Dice,&Temp_Dice) ;
  282.         Black_Score = Temp_Dice.Values[BLACK_PLAYER] ;
  283.         White_Score = Temp_Dice.Values[WHITE_PLAYER] ;
  284.     } else {
  285.         do {
  286.             if (Genetics) {
  287.                 Rand_Rolls = 1 ;
  288.             } else {
  289.                 Rand_Rolls = Int_Rand_Range (MIN_ROLLS,MAX_ROLLS) ;
  290.             }
  291.             for (r = 0 ; r < Rand_Rolls ; r++) {
  292.                 Black_Score = Int_Rand_Range (1,6) ;
  293.                 White_Score = Int_Rand_Range (1,6) ;
  294.                 Draw_Die (Black_Score,1,BLACK_PLAYER) ;
  295.                 Draw_Die (White_Score,2,WHITE_PLAYER) ;
  296.             }
  297.             Seconds_Delay (3) ;
  298.         } while (Black_Score == White_Score) ;
  299.  
  300.         Dice->N_Vals    = 2 ;
  301.         Dice->Values[0] = (char)Black_Score ;
  302.         Dice->Values[1] = (char)White_Score ;
  303.     }
  304.  
  305.     if (Black_Score > White_Score) {
  306.         (*Player) = BLACK_PLAYER ;
  307.     } else {
  308.         (*Player) = WHITE_PLAYER ;
  309.     }
  310.  
  311.     /* Update the dice statistics of the winning player */
  312.     Statistics [(*Player)].N_Throws++ ;
  313.     Statistics [(*Player)].Total += (Black_Score + White_Score) ;
  314. }
  315.  
  316. /*************************************************************************/
  317.  
  318. void Seconds_Delay (short seconds)
  319. /* PURPOSE: Guess. */
  320. {
  321.    time_t Then, Now ;
  322.  
  323.    if (Genetics) {
  324.        return ;  // Go as fast as you can!
  325.    }
  326.  
  327.    (void)time (&Then) ;
  328.    do {
  329.        (void)time (&Now) ;
  330.    } while ((Now - Then) < seconds) ;
  331. }
  332.  
  333. /***************************************************************************/
  334.  
  335. void Record_Move (Player_t Player, Dice_t* Dice,
  336.                   Layout_t Black, Layout_t White)
  337. /*
  338. PURPOSE: To file the move in the global Rec_File.
  339. */
  340. {
  341.     short d ;
  342.  
  343.     if (Rec_File == NULL) {
  344.         Error_Exit ("Writing to NULL Rec_File") ;
  345.     }
  346.  
  347.     fprintf (Rec_File,"\nDice_t = ") ;
  348.  
  349.     fprintf (Rec_File,"{%1d,{",Dice->N_Vals) ;
  350.     for (d=0 ; d < MAX_MOVES-1 ; d++) {
  351.         fprintf (Rec_File,"%1d,",Dice->Values[d]) ;
  352.     }
  353.     fprintf (Rec_File,"%1d}} ; ",Dice->Values[d]) ;
  354.     if (Player == BLACK_PLAYER) {
  355.         fprintf (Rec_File,"/* BLACK */") ;
  356.     } else {
  357.         fprintf (Rec_File,"/* WHITE */") ;
  358.     }
  359.  
  360.     Print_Layouts (Black,White) ;
  361.  
  362.     fprintf (Rec_File,"\n") ;
  363. }
  364.  
  365. /***************************************************************************/
  366.  
  367. void Print_Layouts (Layout_t Black, Layout_t White)
  368. /*
  369. PURPOSE: A debugging printout of the board into the Rec_File
  370. */
  371. {
  372.     Print_Layout (White,WHITE_PLAYER) ;
  373.     Print_Layout (Black,BLACK_PLAYER) ;
  374. }
  375.  
  376. /*************************************************************************/
  377.  
  378. void Print_Layout (Layout_t Layout, Player_t Player)
  379. /*
  380. PURPOSE: To print the layout in an easily machine and human readable form.
  381. */
  382. {
  383.     ushort p,o,r ;
  384.  
  385.     if (Player == BLACK_PLAYER) {
  386.         fprintf (Rec_File,"\n\nLayout_t Black_Lay = {") ;
  387.     } else {
  388.         fprintf (Rec_File,"\n\nLayout_t White_Lay = {") ;
  389.     }
  390.  
  391.     fprintf (Rec_File,"%2d,   /* BAR_I */ ",Layout[BAR_I]) ;
  392.     for (r = 0 ; r < 4 ; r++) {
  393.         o = r*6 ;
  394.         fprintf (Rec_File,"\n                      ") ;
  395.         for (p = 1 ; p <= 6 ; p++) {
  396.             fprintf (Rec_File,"%2d,",Layout[o+p]) ;
  397.         }
  398.     }
  399.     fprintf (Rec_File,"\n                      %2d}; /* HOME_I*/ ",
  400.              Layout[HOME_I]) ;
  401. }
  402.  
  403. /*************************************************************************/
  404.  
  405. #if DRODBAR
  406. Dice_t Test_Dice = {4,{3,3,3,3}} ; /* New layouts = */
  407.  
  408. Layout_t White_Lay = { 0,   /* BAR_I */
  409.                0, 0, 0, 3, 0, 0,
  410.                0, 0, 0, 0, 0, 0,
  411.                0, 0, 0, 0, 0, 0,
  412.                2, 0, 0, 0, 0, 3,
  413.                7}; /* HOME_I*/
  414.  
  415. Layout_t Black_Lay = { 0,   /* BAR_I */
  416.                0, 0, 0, 0, 0, 0,
  417.                0, 0, 1, 0, 0, 3,
  418.                0, 0, 0, 0, 0, 0,
  419.                5, 2, 0, 0, 0, 0,
  420.                4}; /* HOME_I*/
  421.  
  422.  
  423. void Test_Move (void)
  424. /*
  425. PURPOSE: To see how and why the computer moves as he did...
  426. */
  427. {
  428.     Player_t  Player,Opponent ;
  429.     Layout_t  Curr_Lay[2] ; /* The current layouts */
  430.     Transit_t Transit[2] ;  /* The new layouts and how we got there */
  431.  
  432.     Copy_Layout (Curr_Lay[BLACK_PLAYER],Black_Lay) ;
  433.     Copy_Layout (Curr_Lay[WHITE_PLAYER],White_Lay) ;
  434.  
  435.     Player   = WHITE_PLAYER ;
  436.     Opponent = BLACK_PLAYER ;
  437.  
  438.     Draw_Board_Full (Curr_Lay) ;
  439.     Draw_Dice_Pair (&Test_Dice,Player) ;
  440.  
  441.     (void)User_Selects_Move (&Test_Dice,
  442.                          Curr_Lay [Player], Curr_Lay [Opponent],
  443.                      &Transit [Player], &Transit [Opponent],
  444.                      Player) ;
  445.     Show_Transits_And_Kb_Look (&Transit [Player],
  446.                                &Transit [Opponent],
  447.                                Player,PAUSING) ;
  448.     Draw_Board_Quick (Curr_Lay[BLACK_PLAYER],Curr_Lay[WHITE_PLAYER]) ;
  449.     Error_Exit ("") ;
  450. }
  451.  
  452. /*************************************************************************/
  453. #endif
  454. /*************************************************************************/
  455.  
  456. static void Open_Record_File (ushort n)
  457. /*
  458. PURPOSE: To open a file to record the moves of the nth game. The name
  459. is based on the number.
  460. */
  461. {
  462.     char Num_Str[8], Name[16] ;
  463.  
  464.     sprintf (Num_Str,"%d",n) ;
  465.     (void)strcpy (Name,"BG") ;
  466.     (void)strcat (Name,Num_Str) ;
  467.     (void)strcat (Name,".REC") ;
  468.  
  469.     Rec_File = fopen (Name,"w") ; /* Write Text File */
  470.     if (Rec_File == NULL) {
  471.         Error_Exit ("Cannot open record file") ;
  472.     }
  473.     fprintf (Rec_File,"\n/* SEQUENCE OF MOVES, %s */\n",VER_STR) ;
  474. }
  475.  
  476. /*************************************************************************/
  477.  
  478. void Swap_Players (Player_t* Pa, Player_t* Pb)
  479.     /* Swap the two players */
  480. {
  481.     Player_t Temp ;
  482.     Temp     = (*Pa) ;
  483.     (*Pa)    = (*Pb) ;
  484.     (*Pb)    = Temp ;
  485. }
  486.  
  487. /*************************************************************************/
  488.  
  489. /* The options type, a command line option and the address of the
  490. boolean it affects */
  491.  
  492. #define N_OPTIONS 4
  493.  
  494. typedef struct {
  495.     char Name[20] ;
  496.     boolean* Adr ;
  497. } Opt_t ;
  498.  
  499. extern boolean Force_BW ;
  500.  
  501. static Opt_t Options [N_OPTIONS] = {
  502.     {"debug",   &Debugging},    /* Writes all moves to a file */
  503.     {"genetics",&Genetics},     /* All-Computer tournament, no interaction */
  504.     {"mono",    &Force_BW}} ;   /* Forces black and white display */
  505.  
  506. static void Command_Line_Read (int argc, char* argv[])
  507. /*
  508. PURPOSE: To see if the user has typed any special command line
  509.          options, and to set the options accordingly.
  510. */
  511. {
  512.     short a,o ;
  513.  
  514.     for (a = 0 ; a < argc ; a++) {
  515.         for (o = 0 ; o < N_OPTIONS ; o++) {
  516.             if (strcmpi (argv[a],Options[o].Name) == SAME_STRING) {
  517.                 (*Options[o].Adr) = TRUE ;
  518.             }
  519.         }
  520.     }
  521. }
  522.  
  523. /*************************************************************************/
  524.  
  525. static void Update_Score (Player_t Player, int Points)
  526. /*
  527. PURPOSE: To update the stats for the player, display them, and set
  528.          No_Cube to the correct value.
  529. */
  530. {
  531.     extern int     Double_Value ;
  532.     extern int     Target_Score ;
  533.     extern boolean No_Cube ;
  534.  
  535.     Statistics[Player].Games_Won+= (Double_Value*Points) ;
  536.     Draw_Stats () ;
  537.  
  538.     if (!No_Cube) {
  539.         /* Either before or after freeze */
  540.         if (Statistics[BLACK_PLAYER].Games_Won != Statistics[WHITE_PLAYER].Games_Won) {
  541.              if (Statistics[Player].Games_Won == (Target_Score-1)) {
  542.                  Print_Message (NO_CUBE_MSG) ;
  543.                  No_Cube = TRUE ;
  544.              } else {
  545.                  No_Cube = FALSE ;
  546.              }
  547.         } else {
  548.             No_Cube = FALSE ;
  549.         }
  550.     } else {
  551.         /* It has been TRUE, it last for one game only */
  552.         No_Cube = FALSE ;
  553.     }
  554. }
  555.  
  556. /*************************************************************************/
  557.  
  558. static boolean Game_Over (Player_t Human)
  559. /*
  560. PURPOSE: To return TRUE if the whole set of matches is finished.
  561. If the Human is playing then we write some messages for him too.
  562. */
  563. {
  564.     if (Human != NULL_PLAYER) {
  565.          if (Statistics[OPPONENT(Human)].Games_Won >= Target_Score) {
  566.              Print_Message (COM_WINS_SET_MSG) ;
  567.              Seconds_Delay (2) ;
  568.              return (TRUE) ;
  569.          } else if (Statistics[Human].Games_Won >= Target_Score) {
  570.              Print_Message (YOU_WIN_SET_MSG) ;
  571.              Seconds_Delay (2) ;
  572.              return (TRUE) ;
  573.          } else {
  574.              return (FALSE) ;
  575.          }
  576.     } else {
  577.         if (Statistics [BLACK_PLAYER].Games_Won >= Target_Score) {
  578.             return (TRUE) ;
  579.         } else if (Statistics [WHITE_PLAYER].Games_Won >= Target_Score) {
  580.             return (TRUE) ;
  581.         } else {
  582.             return (FALSE) ;
  583.         }
  584.     }
  585. }
  586.  
  587. /*************************************************************************/
  588.